package com.xyy.saas.payment.payment.core.service.impl;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.PinganLoanOffflagEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.param.PinganLoanDetailVo;
import com.xyy.saas.payment.cores.param.PinganLoanMyLoanVo;
import com.xyy.saas.payment.cores.vo.*;
import com.xyy.saas.payment.dao.model.PayFinanceRefundPlan;
import com.xyy.saas.payment.dao.model.PinganLoanDetailQuery;
import com.xyy.saas.payment.dao.model.PinganLoanMyLoanQuery;
import com.xyy.saas.payment.dto.PinganLoanMyLoanRecordDto;
import com.xyy.saas.payment.payment.core.service.PinganLoanService;
import com.xyy.saas.payment.service.PinganLoanFinanceRefundPlanService;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.PojoConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

@Slf4j
@Service
public class PaymentLoanServiceImpl implements PinganLoanService {
    @Autowired
    private PinganLoanFinanceRefundPlanService pinganLoanFinanceRefundPlanService;

    /**
     * 我的平安贷
     */
    @Override
    public ResultVO<PinganLoanMyLoanDto> myLoan(PinganLoanMyLoanVo param) {
        log.info("查询我的平安贷请求数据：{}", JSON.toJSONString(param));
        try {
            String currentDate = DateUtil.format(new Date(), DateUtil.DATEFORMATMONTH);
            // 参数校验
            if (StringUtils.isBlank(param.getMerchantId())) {
                throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
            }
            List<PinganLoanMyLoanDetailDto> records = new ArrayList<>();
            PinganLoanMyLoanDto result = PinganLoanMyLoanDto.builder().curPrincipalAmountBalance("0.00").records(records).build();

            // 拼装查询参数
            PinganLoanMyLoanQuery query = new PinganLoanMyLoanQuery();
            query.setBillCode(param.getBillCode());
            query.setMerchantId(param.getMerchantId());
            if (null != param.getQueryMonth()) {
                query.setPayDayStart(DateUtil.difMonthPingan(new Date(), param.getQueryMonth() - 1));
                query.setPayDayEnd(DateUtil.format(new Date(), DateUtil.DATEFORMATSECOND));
            }

            // 查询应还本金
            PayFinanceRefundPlan payFinanceRefundPlan = pinganLoanFinanceRefundPlanService.curPrincipalAmountBalance(param.getMerchantId());
            if (null == payFinanceRefundPlan || null == payFinanceRefundPlan.getPayDay()) {
                return ResultVO.createSuccess(result);
            }
            result.setCurPrincipalAmountBalance((new BigDecimal(payFinanceRefundPlan.getCurPrincipalAmount()).subtract(new BigDecimal(payFinanceRefundPlan.getActPrincipalAmount()))).toString());

            // 验证是否查询明细数据
            if (null != param.getDetail() && param.getDetail() == 1) {
                return ResultVO.createSuccess(result);
            }

            // 查询明细数据
            log.info("查询我的平安贷请求数据：{}", JSON.toJSONString(param));
            List<PinganLoanMyLoanRecordDto> pinganLoanMyLoanRecordDtos = pinganLoanFinanceRefundPlanService.myLoan(query);

            if (StringUtils.isNotBlank(param.getBillCode()) && CollectionUtils.isEmpty(pinganLoanMyLoanRecordDtos)) {
                PinganLoanMyLoanDetailDto dto = PinganLoanMyLoanDetailDto.builder().billCode(param.getBillCode()).payoffflag(PinganLoanOffflagEnum.NOT_CLEAR.getCode()).build();
                logicProcess(dto, currentDate);
                records.add(dto);
                result.setRecords(records);
                return ResultVO.createSuccess(result);
            }

            // 处理响应数据
            Set<String> haveMonths = new HashSet<>();
            if (!CollectionUtils.isEmpty(pinganLoanMyLoanRecordDtos)) {
                for (PinganLoanMyLoanRecordDto pinganLoanMyLoanRecordDto : pinganLoanMyLoanRecordDtos) {
                    PinganLoanMyLoanDetailDto loanDetailDto = PojoConvertUtil.convertPojo(pinganLoanMyLoanRecordDto, PinganLoanMyLoanDetailDto::new);
                    logicProcess(loanDetailDto, currentDate);
                    records.add(loanDetailDto);
                    haveMonths.add(loanDetailDto.getBillCode());
                }
            }

            // 填充数据：仅当不依据状态筛选时需要填充数据
            if (StringUtils.isBlank(param.getBillCode())) {
                String firstMonth = DateUtil.format(payFinanceRefundPlan.getPayDay(), DateUtil.DATEFORMATMONTH);
                String queryStart = StringUtils.isBlank(query.getPayDayStart()) ? "" : DateUtil.format(DateUtil.string2Date(query.getPayDayStart()), DateUtil.DATEFORMATMONTH);
                String startMonth = (StringUtils.isBlank(queryStart) || firstMonth.compareTo(queryStart) > 0 ? firstMonth : queryStart);
                List<String> betweenMonths = DateUtil.getBetweenMonths(startMonth, DateUtil.format(new Date(), DateUtil.DATEFORMATMONTH), DateUtil.DATEFORMATMONTH);
                for (String betweenMonth : betweenMonths) {
                    if (!haveMonths.contains(betweenMonth)) {
                        PinganLoanMyLoanDetailDto dto = PinganLoanMyLoanDetailDto.builder().billCode(betweenMonth).payoffflag(PinganLoanOffflagEnum.NOT_CLEAR.getCode()).build();
                        logicProcess(dto, currentDate);
                        records.add(dto);
                    }
                }
            }

            // 过滤状态
            if (null != param.getPayoffflag() && CollectionUtils.isNotEmpty(records)) {
                Iterator<PinganLoanMyLoanDetailDto> iterator = records.iterator();
                while (iterator.hasNext()) {
                    PinganLoanMyLoanDetailDto detailDto = iterator.next();
                    if (!param.getPayoffflag().equals(detailDto.getPayoffflag())) {
                        iterator.remove();
                    }
                }
            }

            // 排序
            records.sort((o1, o2) -> o2.getBillCode().compareTo(o1.getBillCode()));
            return ResultVO.createSuccess(result);
        } catch (PaymentException pe) {
            log.error("查询我的平安贷异常:{}", pe.getErrCode(), pe);
            return ResultVO.createError(pe.getErrCode(), pe.getErrMsg());
        } catch (Exception e) {
            log.error("查询我的平安贷异常:{}", e.getMessage(), e);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    /**
     * 平安贷明细查询
     */
    @Override
    public ResultVO<List<PinganLoanDetailDto>> loanDetail(PinganLoanDetailVo param) {
        log.info("查询平安贷明细请求数据：{}", JSON.toJSONString(param));
        try {
            // 参数校验
            if (StringUtils.isBlank(param.getMerchantId()) || StringUtils.isBlank(param.getBillCode())) {
                throw new PaymentException(ResultCodeEnum.PARAM_ERROR);
            }
            List<PinganLoanDetailDto> result = new ArrayList<>();

            // 拼装查询参数
            PinganLoanDetailQuery query = new PinganLoanDetailQuery();
            query.setMerchantId(param.getMerchantId());
            query.setPayoffflag(param.getPayoffflag());
            query.setPayDayStart(param.getBillCode() + "-01");
            query.setPayDayEnd(DateUtil.nextMonth(query.getPayDayStart(), DateUtil.DATEFORMATDAY));

            // 查询数据
            log.info("查询平安贷明细请求数据：{}", JSON.toJSONString(param));
            List<PayFinanceRefundPlan> payFinanceRefundPlans = pinganLoanFinanceRefundPlanService.loanDetail(query);
            if (CollectionUtils.isEmpty(payFinanceRefundPlans)) {
                ResultVO.createSuccess(result);
            }

            // 处理响应数据
            Map<String, List<PinganLoanDetailRecordDto>> resultTmp = new LinkedHashMap<>();
            for (PayFinanceRefundPlan payFinanceRefundPlan : payFinanceRefundPlans) {
                logicProcess(resultTmp, payFinanceRefundPlan);
            }
            for (String resultMapKey : resultTmp.keySet()) {
                PinganLoanDetailDto detailDto = PinganLoanDetailDto.builder().billDate(resultMapKey).records(resultTmp.get(resultMapKey)).build();
                result.add(detailDto);
            }
            return ResultVO.createSuccess(result);
        } catch (PaymentException pe) {
            log.error("查询平安贷明细异常:{}", pe.getErrCode(), pe);
            return ResultVO.createError(pe.getErrCode(), pe.getErrMsg());
        } catch (Exception e) {
            log.error("查询平安贷明细异常:{}", e.getMessage(), e);
            return ResultVO.createError(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    /**
     * 逻辑处理 - 账单明细
     */
    private static void logicProcess(Map<String, List<PinganLoanDetailRecordDto>> result, PayFinanceRefundPlan payFinanceRefundPlan) {
        String key = DateUtil.format(payFinanceRefundPlan.getPayDay(), "M月d日");
        List<PinganLoanDetailRecordDto> records = result.containsKey(key) ? result.get(key) : new ArrayList<>();
        PinganLoanDetailRecordDto dto = PojoConvertUtil.convertPojo(payFinanceRefundPlan, PinganLoanDetailRecordDto::new);
        dto.setCurPrincipalAmountBalance((new BigDecimal(payFinanceRefundPlan.getCurPrincipalAmount()).subtract(new BigDecimal(payFinanceRefundPlan.getActPrincipalAmount()))).toString());
        dto.setCurRepayDate(DateUtil.format(payFinanceRefundPlan.getCurRepayDate(), DateUtil.DATEFORMATDAY));
        dto.setActRepayDate(DateUtil.format(payFinanceRefundPlan.getActRepayDate(), DateUtil.DATEFORMATDAY));
        dto.setPayDayFormat(DateUtil.format(payFinanceRefundPlan.getPayDay(), DateUtil.DATEFORMATDAY));
        records.add(dto);
        result.put(key, records);
    }

    /**
     * 逻辑处理 - 我的平安贷
     */
    private static void logicProcess(PinganLoanMyLoanDetailDto loanDetailDto, String currentDate) throws ParseException {
        // 计算 账单名称描述  2023-07 -> 2023年7月账单
        if (currentDate.equals(loanDetailDto.getBillCode())) {
            loanDetailDto.setBillName("本月账单");
            loanDetailDto.setPayoffflag(PinganLoanOffflagEnum.UN_DIVIDE.getCode());
        } else {
            loanDetailDto.setBillName(DateUtil.format(DateUtil.string2Date(loanDetailDto.getBillCode() + "-01"), "yyyy年M月账单"));
        }
        // 计算 贴息截止日
        loanDetailDto.setSubsidyInterestDate(DateUtil.nextMonth(loanDetailDto.getBillCode() + "-15", DateUtil.DATEFORMATDAY));
        // 若为无需还款，则不进行后续处理
        if (null != loanDetailDto.getPayoffflag() && PinganLoanOffflagEnum.NOT_CLEAR.getCode().equals(loanDetailDto.getPayoffflag())) {
            return;
        }
        // 计算 剩余应还本金  应还本金 - 已还本金
        loanDetailDto.setCurPrincipalAmountBalance((new BigDecimal(loanDetailDto.getCurPrincipalAmount()).subtract(new BigDecimal(loanDetailDto.getActPrincipalAmount()))).toString());
        // 计算 结清状态
        if (currentDate.equals(loanDetailDto.getBillCode())) {
            loanDetailDto.setPayoffflag(PinganLoanOffflagEnum.UN_DIVIDE.getCode());
        } else {
            if (new BigDecimal(loanDetailDto.getCurPrincipalAmount()).equals(new BigDecimal(loanDetailDto.getActPrincipalAmount()))) {
                loanDetailDto.setPayoffflag(PinganLoanOffflagEnum.CLEAR.getCode());
            } else {
                loanDetailDto.setPayoffflag(PinganLoanOffflagEnum.UN_CLEAR.getCode());
            }
        }
    }

}
